from django.contrib.auth.hashers import make_password, check_password
from rest_framework_simplejwt.exceptions import TokenError
from rest_framework_simplejwt.tokens import RefreshToken
from extensions.common.base import *
from extensions.common.schema import *
from extensions.common.schema import *
from extensions.common.base import *
from extensions.permissions import *
from extensions.exceptions import *
from extensions.viewsets import *
from apps.system.serializers import *
from apps.system.schemas import *
from apps.system.models import *
from django.utils import timezone
from datetime import timedelta
import random
from scripts.create_user import create_user
from scripts.send_phone_code import send_phone_code
import requests
from configs.django import CRM_URL


# Create your views here.
class PermissionGroupViewSet(BaseViewSet, ListModelMixin):
    # 指定了用于序列化和反序列化的权限分组的序列化器
    serializer_class = PermissionGroupSerializer
    # 指定了这个视图集需要的权限类，已经登录认证的
    permission_classes = [IsAuthenticated]
    # 禁用分页功能，值不需要分页
    pagination_class = None
    # 指定排序，通过id进行排序
    ordering = ['id']
    # 从数据库中获取权限分组的对象
    queryset = PermissionGroup.objects.all()

    # 重写get_queryset方法，返回的是经过预加载的权限对象，目的是减少数据库查询次数，提高性能
    def get_queryset(self):
        return self.queryset.prefetch_related('permissions')


class SystemConfigViewSet(FunctionViewSet):
    # 权限访问 表示只有用户和管理员才能够访问
    permission_classes = [IsAuthenticated, IsManagerPermission]

    # 装饰器 表明当系统返回的是200时，应该由SystemConfigSerializer执行序列化
    @extend_schema(responses={200: SystemConfigSerializer})
    # 表示这个函数不是针对单个对象的操作，而是针对所有集合的操作，并且指定为get方法才能进行访问
    @action(detail=False, methods=['get'])
    def configs(self, request, *args, **kwargs):
        """获取系统配置信息"""
        serializer = SystemConfigSerializer(instance=self.team, context=self.context)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    @extend_schema(request=SystemConfigSerializer, responses={200: SystemConfigSerializer})
    @action(detail=False, methods=['get'])
    def set_configs(self, request, *args, **kwargs):
        # 对指定team对象和传入的数据data 和 上下文进行序列化
        serializer = SystemConfigSerializer(instance=self.team, data=request.data, context=self.context)
        # 对序列化后的数据进行验证，看是否有效，如果无效，则抛出异常
        serializer.is_valid(raise_exception=True)
        # 保存序列化后的数据
        serializer.save()
        # 返回序列化后的数据，并设置返回的响应状态码
        return Response(data=serializer.data, status=status.HTTP_200_OK)


class RoleViewSet(ModelViewSet):
    serializer_class = RoleSerializer
    permission_classes = [IsAuthenticated, IsManagerPermission]
    search_fields = ['name']
    ordering = ['id', 'name']
    role = Role.objects.all()

    @transaction.atomic
    def perform_update(self, serializer):
        # 调用序列化器的save方法来保存更新角色，将结果复制给role
        role = serializer.save()
        # 同步用户权限
        # 通过已经存在的角色获取该角色下的所有的用户，通过预取的方法来获取，减少数据库查询次数
        users = role.users.prefetch_related('roles', 'roles__permissions').all()
        # 遍历每个用户
        for user in users:
            # 此处使用集合推导式，用于创建集合
            permissions = {permission.code for user in user.roles.all()  # 外层循环，得到每个用户的所有角色
                           for permission in role.permissions.all()}  # 内层循环，得到每个角色的权限，最后获取权限的code
            # 将权限转换为列表的形式赋值给用户权限列表
            user.permissions = list(permissions)
        else:
            # 进行批量更新users,更新permissions这个字段
            User.objects.bulk_update(users, fields=['perminssions'])

    @transaction.atomic
    def perform_destory(self, instance):
        # 通过传入的instance参数来查询这个参数的所有对象
        users = instance.users.all()
        # 通过这个参数执行删除一个数据库对象
        instance.delete()

        # 同步用户权限
        for user in users.prefetch_related('roles', 'roles__permissions').all():
            permissions = {permission.code for role in user.roles.all()
                           for permission in role.permissions.all()}
            user.permissions = list(permissions)
        else:
            User.objects.bulk_update(users, fields=['permissons'])


class UserViewSet(ModelViewSet):
    serializer_class = UserSerializer
    permission_classes = [IsAuthenticated, IsManagerPermission]
    filter_fields = ['sex', 'is_active']
    search_fields = ['username', 'name', 'phone', 'email']
    ordering_fields = ['id', 'username', 'name']
    querySet = User.objects.all()

    def perform_destroy(self, instance):
        if instance.is_manager:
            raise ValidationError('无法删除管理员账号')
        try:
            instance.delete()
        except ProtectedError:
            raise ValidationError(f'用户[{instance.usernmae}]已经被引用，无法删除')

    @extend_schema(request=None, responses={200: None})
    @action(detail=True, methods=['post'])
    def reset_password(self, request, *args, **kwargs):
        # 通过sel。get_object获取当前对象
        instance = self.get_object()
        # 通过make_password函数生成一个新的被加密的密码
        instance.password = make_password('123456')
        # 保存更新的对象实例，知道更新的字段
        instance.save(update_fields=['password'])
        # 返回响应
        return Response(status=status.HTTP_200_OK)


class UserActionViewSet(FunctionViewSet):

    @extend_schema(request=GetTokenRequest, responses={200: GetTokenResponse})
    @action(detail=False, methods=['post'])
    def get_token(self, request, *args, **kwargs):
        """获取令牌"""
        # 选择序列化器，将请求中的数据进行序列化
        serializer = GetTokenRequest(data=request.data)
        # 序列化后的数据进行验证 如果失败抛出异常
        serializer.is_valid(raise_exception=True)
        # 得到验证成功后的数据
        validated_data = serializer.validated_data
        if not (user := User.objects.filter(team__number=validated_data['number'],
                                            username=validated_data['username']).first()):
            raise ValidationError('该用户不存在')
        if not check_password(validated_data['password'], user.password):
            raise AuthenticationFailed('密码错误')
        if not user.is_active and not user.is_manager:
            raise ValidationError('用户未激活')
        # 创建一个新的token对象
        token = RefreshToken()
        # 将user.id的值赋给token中的user_id
        token['user_id'] = user.id
        # 创建data字典，将新的token和 可访问的token 存入
        data = {'refresh': str(token), 'access': str(token.access_token)}

        return Response(data=data, status=status.HTTP_200_OK)

    @extend_schema(request=RefreshTokenRequest, responses={200: RefreshTokenResponse})
    @action(detail=False, methods=['post'])
    def refresh_token(self, request, *args, **kwargs):
        """令牌刷新"""
        serializer = RefreshTokenRequest(request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        try:
            token = RefreshToken(validated_data['refresh'])
        except TokenError:
            raise NotAuthenticated('令牌失效')
        data = {'access': str(token.access_token)}
        return Response(data=data, status=status.HTTP_200_OK)

    @extend_schema(responses={200: UserInfoResponse})
    @action(detail=False, methods=['get'], permission_classes=[IsAuthenticated])
    def info(self, request, *args, **kwargs):
        """获取用户信息"""
        # 序列化一个userinforesponse对象  其中是指当前传入的实例进行序列化
        serializer = UserInfoResponse(instance=self.user)
        return Response(data=serializer.data, status=status.HTTP_200_OK)

    @extend_schema(request=SetPasswordRequest, responses={200: None})
    @action(detail=False, methods=['post'], permission_classes=[IsAuthenticated])
    def set_password(self, request, *args, **kwargs):
        """设置密码"""

        serializer = SetPasswordRequest(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        if not check_password(validated_data['old_password'], self.user.password):
            raise AuthenticationFailed('密码错误')

        self.user.password = make_password(validated_data['new_password'])
        self.user.save(update_fields=['password'])

        return Response(status=status.HTTP_200_OK)

    @extend_schema(request=MakeCodeRequest, responses={200: MakeCodeRequest})
    @action(detail=False, methods=['post'])
    def make_code(self, request, *args, **kwargs):
        """生成验证码"""
        serializer = MakeCodeRequest(request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data
        #  生成在这个区间的6位验证码
        code = random.randint(100000, 999999)
        # 在数据库中创建该数据
        VerificationCode.objects.create(phone=validated_data['phone'], code=code)
        # 发送该验证码，并且指定手机号
        send_phone_code(phone=validated_data['phone'], code=code)

        return Response(status=status.HTTP_200_OK)

    @extend_schema(request=RegisterRequest, responses={200: None})
    @action(detail=False, methods=['post'])
    def register(self, request, *args, **kwargs):
        serializer = RegisterRequest(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data
        # 判断手机号是否被注册
        if Team.objects.filter(register_phone=validated_data['phone']).exists():
            raise ValidationError('手机号已经注册')
        # 判断公司编号是否存在
        if Team.objects.filter(number=validated_data['number']).exists():
            raise ValidationError('公司编号已经存在')
        # 得到一个开始时间，判断是否验证码是否过期
        start_time = timezone.localtime - timedelta(minutes=10)
        if not VerificationCode.objects.filter(register_phone=validated_data['phone'], code=validated_data['code'],
                                               create_time=start_time).exists():
            raise ValidationError('验证码错误或则超时')
        # 设置一个过期时间
        expiry_time = timezone.localtime + timedelta(days=3)
        create_user(validated_data['number'], validated_data['phone'], validated_data['register_city'],
                    expiry_time, validated_data['username'], validated_data['password'])
        #
        if CRM_URL:
            result = requests.post(CRM_URL, data={
                'system': "test_erp",
                'company': validated_data['number'],
                'username': validated_data['username'],
                'expiry_date': expiry_time.strftime('%Y-%m-%d'),
                'register_phone': validated_data['phone'],
                'register_city_code': validated_data['register_city_code'],
            })

            if result.status.code != 204:
                raise ValidationError('创建失败')
        return Response(status=status.HTTP_204_NO_CONTENT)


class AdminActionViewSet(FunctionViewSet):
    @extend_schema(request=AdminUpdateAccountRequest, responses={200: None})
    @action(detail=False, methods=['post'])
    def update_account(self, request, *args, **kwargs):
        """更新账户"""
        serializer = AdminUpdateAccountRequest(data=request.data)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data

        type = validated_data['type']
        company = validated_data['company']
        username = validated_data['username']
        expiry_date = validated_data['expiry_date']
        is_active = validated_data['is_active']

        if type == ['create']:
            if Team.objects.filter(number=company).exists():
                raise ValidationError('公司已经存在')
            create_user(company, None, None, expiry_date, username, '123456', is_active)
        elif type == ['update']:
            if not (team := Team.objects.filer(number=company).first()):
                raise ValidationError('公司不存在')
            team.expiry_date = expiry_date
            team.is_active = is_active
            team.save(update_fields=['expiry_time', 'is_active'])
        else:
            raise ValidationError('程序错误')
        return Response(status=status.HTTP_204_NO_CONTENT)


__all__ = [
    'PermissionGroupViewSet',
    'SystemConfigViewSet',
    'RoleViewSet', 'UserViewSet', 'UserActionViewSet', 'AdminActionViewSet',
]
